package org.zero.manager;

import java.util.Objects;
import java.util.concurrent.Callable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.SerializationUtils;

/**
 * @author Zero (cnzeropro@qq.com)
 * @date 2021/10/26 17:20
 */
@Slf4j
public class RedisCache implements Cache {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private final String name;

    public RedisCache(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public Object getNativeCache() {
        return this.redisTemplate;
    }

    @Override
    public ValueWrapper get(Object key) {
        Object object = redisTemplate.execute((RedisCallback<Object>) connection -> {
            byte[] keyBytes = key.toString().getBytes();
            byte[] value = connection.get(keyBytes);
            if (value == null) {
                log.info("未命中，缓存【{}】不存在", key);
                return null;
            }
            return SerializationUtils.deserialize(value);
        });

        if (object == null) {
            return null;
        }

        ValueWrapper valueWrapper = new SimpleValueWrapper(object);

        log.info("命中，通过【{}】获取到缓存：{}", key, valueWrapper.get());

        return valueWrapper;
    }

    @Override
    public <T> T get(Object key, Class<T> type) {
        return (T) get(key);
    }

    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        return null;
    }

    @Override
    public void put(Object key, Object value) {
        // 默认失效时间：1d
        final long liveTime = 86400;

        redisTemplate.execute((RedisCallback<Long>) connection -> {
            byte[] keyBytes = key.toString().getBytes();
            byte[] valueBytes = SerializationUtils.serialize(value);
            connection.set(keyBytes, Objects.requireNonNull(valueBytes));
            connection.expire(keyBytes, liveTime);
            return 1L;
        });

        log.info("已添加缓存：{} - {}", key, value);
    }

    @Override
    public void evict(final Object key) {
        redisTemplate.execute((RedisCallback<Long>) connection -> connection.del(key.toString().getBytes()));

        log.info("已删除缓存：{}", key);
    }

    @Override
    public void clear() {
        redisTemplate.execute((RedisCallback<String>) connection -> {
            connection.flushDb();
            return "ok";
        });

        log.info("已清空缓存");
    }
}
